<!DOCTYPE HTML>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>New Parser test</title>
<style>
#input, #output, #parseTree {
	width:500px;
	height:200px;
}	
</style>
<script>
function validVar(c){	
	return c===170||c===181||c===186||c>=192&&c<=214||c>=216&&c<=246||c>=248&&c<=705||c>=710&&c<=721||c>=736&&c<=740||c===748||c===750||c>=880&&c<=884||c>=886&&c<=887||c>=890&&c<=893||c===902||c>=904&&c<=906||c===908||c>=910&&c<=929||c>=931&&c<=1013||c>=1015&&c<=1153||c>=1162&&c<=1319||c>=1329&&c<=1366||c===1369||c>=1377&&c<=1415||c>=1488&&c<=1514||c>=1520&&c<=1522||c>=1568&&c<=1610||c>=1646&&c<=1647||c>=1649&&c<=1747||c===1749||c>=1765&&c<=1766||c>=1774&&c<=1775||c>=1786&&c<=1788||c===1791||c===1808||c>=1810&&c<=1839||c>=1869&&c<=1957||c===1969||c>=1994&&c<=2026||c>=2036&&c<=2037||c===2042||c>=2048&&c<=2069||c===2074||c===2084||c===2088||c>=2112&&c<=2136||c===2208||c>=2210&&c<=2220||c>=2308&&c<=2361||c===2365||c===2384||c>=2392&&c<=2401||c>=2417&&c<=2423||c>=2425&&c<=2431||c>=2437&&c<=2444||c>=2447&&c<=2448||c>=2451&&c<=2472||c>=2474&&c<=2480||c===2482||c>=2486&&c<=2489||c===2493||c===2510||c>=2524&&c<=2525||c>=2527&&c<=2529||c>=2544&&c<=2545||c>=2565&&c<=2570||c>=2575&&c<=2576||c>=2579&&c<=2600||c>=2602&&c<=2608||c>=2610&&c<=2611||c>=2613&&c<=2614||c>=2616&&c<=2617||c>=2649&&c<=2652||c===2654||c>=2674&&c<=2676||c>=2693&&c<=2701||c>=2703&&c<=2705||c>=2707&&c<=2728||c>=2730&&c<=2736||c>=2738&&c<=2739||c>=2741&&c<=2745||c===2749||c===2768||c>=2784&&c<=2785||c>=2821&&c<=2828||c>=2831&&c<=2832||c>=2835&&c<=2856||c>=2858&&c<=2864||c>=2866&&c<=2867||c>=2869&&c<=2873||c===2877||c>=2908&&c<=2909||c>=2911&&c<=2913||c===2929||c===2947||c>=2949&&c<=2954||c>=2958&&c<=2960||c>=2962&&c<=2965||c>=2969&&c<=2970||c===2972||c>=2974&&c<=2975||c>=2979&&c<=2980||c>=2984&&c<=2986||c>=2990&&c<=3001||c===3024||c>=3077&&c<=3084||c>=3086&&c<=3088||c>=3090&&c<=3112||c>=3114&&c<=3123||c>=3125&&c<=3129||c===3133||c>=3160&&c<=3161||c>=3168&&c<=3169||c>=3205&&c<=3212||c>=3214&&c<=3216||c>=3218&&c<=3240||c>=3242&&c<=3251||c>=3253&&c<=3257||c===3261||c===3294||c>=3296&&c<=3297||c>=3313&&c<=3314||c>=3333&&c<=3340||c>=3342&&c<=3344||c>=3346&&c<=3386||c===3389||c===3406||c>=3424&&c<=3425||c>=3450&&c<=3455||c>=3461&&c<=3478||c>=3482&&c<=3505||c>=3507&&c<=3515||c===3517||c>=3520&&c<=3526||c>=3585&&c<=3632||c>=3634&&c<=3635||c>=3648&&c<=3654||c>=3713&&c<=3714||c===3716||c>=3719&&c<=3720||c===3722||c===3725||c>=3732&&c<=3735||c>=3737&&c<=3743||c>=3745&&c<=3747||c===3749||c===3751||c>=3754&&c<=3755||c>=3757&&c<=3760||c>=3762&&c<=3763||c===3773||c>=3776&&c<=3780||c===3782||c>=3804&&c<=3807||c===3840||c>=3904&&c<=3911||c>=3913&&c<=3948||c>=3976&&c<=3980||c>=4096&&c<=4138||c===4159||c>=4176&&c<=4181||c>=4186&&c<=4189||c===4193||c>=4197&&c<=4198||c>=4206&&c<=4208||c>=4213&&c<=4225||c===4238||c>=4256&&c<=4293||c===4295||c===4301||c>=4304&&c<=4346||c>=4348&&c<=4680||c>=4682&&c<=4685||c>=4688&&c<=4694||c===4696||c>=4698&&c<=4701||c>=4704&&c<=4744||c>=4746&&c<=4749||c>=4752&&c<=4784||c>=4786&&c<=4789||c>=4792&&c<=4798||c===4800||c>=4802&&c<=4805||c>=4808&&c<=4822||c>=4824&&c<=4880||c>=4882&&c<=4885||c>=4888&&c<=4954||c>=4992&&c<=5007||c>=5024&&c<=5108||c>=5121&&c<=5740||c>=5743&&c<=5759||c>=5761&&c<=5786||c>=5792&&c<=5866||c>=5870&&c<=5872||c>=5888&&c<=5900||c>=5902&&c<=5905||c>=5920&&c<=5937||c>=5952&&c<=5969||c>=5984&&c<=5996||c>=5998&&c<=6000||c>=6016&&c<=6067||c===6103||c===6108||c>=6176&&c<=6263||c>=6272&&c<=6312||c===6314||c>=6320&&c<=6389||c>=6400&&c<=6428||c>=6480&&c<=6509||c>=6512&&c<=6516||c>=6528&&c<=6571||c>=6593&&c<=6599||c>=6656&&c<=6678||c>=6688&&c<=6740||c===6823||c>=6917&&c<=6963||c>=6981&&c<=6987||c>=7043&&c<=7072||c>=7086&&c<=7087||c>=7098&&c<=7141||c>=7168&&c<=7203||c>=7245&&c<=7247||c>=7258&&c<=7293||c>=7401&&c<=7404||c>=7406&&c<=7409||c>=7413&&c<=7414||c>=7424&&c<=7615||c>=7680&&c<=7957||c>=7960&&c<=7965||c>=7968&&c<=8005||c>=8008&&c<=8013||c>=8016&&c<=8023||c===8025||c===8027||c===8029||c>=8031&&c<=8061||c>=8064&&c<=8116||c>=8118&&c<=8124||c===8126||c>=8130&&c<=8132||c>=8134&&c<=8140||c>=8144&&c<=8147||c>=8150&&c<=8155||c>=8160&&c<=8172||c>=8178&&c<=8180||c>=8182&&c<=8188||c===8305||c===8319||c>=8336&&c<=8348||c===8450||c===8455||c>=8458&&c<=8467||c===8469||c>=8473&&c<=8477||c===8484||c===8486||c===8488||c>=8490&&c<=8493||c>=8495&&c<=8505||c>=8508&&c<=8511||c>=8517&&c<=8521||c===8526||c>=8544&&c<=8584||c>=11264&&c<=11310||c>=11312&&c<=11358||c>=11360&&c<=11492||c>=11499&&c<=11502||c>=11506&&c<=11507||c>=11520&&c<=11557||c===11559||c===11565||c>=11568&&c<=11623||c===11631||c>=11648&&c<=11670||c>=11680&&c<=11686||c>=11688&&c<=11694||c>=11696&&c<=11702||c>=11704&&c<=11710||c>=11712&&c<=11718||c>=11720&&c<=11726||c>=11728&&c<=11734||c>=11736&&c<=11742||c===11823||c>=12293&&c<=12295||c>=12321&&c<=12329||c>=12337&&c<=12341||c>=12344&&c<=12348||c>=12353&&c<=12438||c>=12445&&c<=12447||c>=12449&&c<=12538||c>=12540&&c<=12543||c>=12549&&c<=12589||c>=12593&&c<=12686||c>=12704&&c<=12730||c>=12784&&c<=12799||c>=13312&&c<=19893||c>=19968&&c<=40908||c>=40960&&c<=42124||c>=42192&&c<=42237||c>=42240&&c<=42508||c>=42512&&c<=42527||c>=42538&&c<=42539||c>=42560&&c<=42606||c>=42623&&c<=42647||c>=42656&&c<=42735||c>=42775&&c<=42783||c>=42786&&c<=42888||c>=42891&&c<=42894||c>=42896&&c<=42899||c>=42912&&c<=42922||c>=43000&&c<=43009||c>=43011&&c<=43013||c>=43015&&c<=43018||c>=43020&&c<=43042||c>=43072&&c<=43123||c>=43138&&c<=43187||c>=43250&&c<=43255||c===43259||c>=43274&&c<=43301||c>=43312&&c<=43334||c>=43360&&c<=43388||c>=43396&&c<=43442||c===43471||c>=43520&&c<=43560||c>=43584&&c<=43586||c>=43588&&c<=43595||c>=43616&&c<=43638||c===43642||c>=43648&&c<=43695||c===43697||c>=43701&&c<=43702||c>=43705&&c<=43709||c===43712||c===43714||c>=43739&&c<=43741||c>=43744&&c<=43754||c>=43762&&c<=43764||c>=43777&&c<=43782||c>=43785&&c<=43790||c>=43793&&c<=43798||c>=43808&&c<=43814||c>=43816&&c<=43822||c>=43968&&c<=44002||c>=44032&&c<=55203||c>=55216&&c<=55238||c>=55243&&c<=55291||c>=63744&&c<=64109||c>=64112&&c<=64217||c>=64256&&c<=64262||c>=64275&&c<=64279||c===64285||c>=64287&&c<=64296||c>=64298&&c<=64310||c>=64312&&c<=64316||c===64318||c>=64320&&c<=64321||c>=64323&&c<=64324||c>=64326&&c<=64433||c>=64467&&c<=64829||c>=64848&&c<=64911||c>=64914&&c<=64967||c>=65008&&c<=65019||c>=65136&&c<=65140||c>=65142&&c<=65276||c>=65313&&c<=65338||c>=65345&&c<=65370||c>=65382&&c<=65470||c>=65474&&c<=65479||c>=65482&&c<=65487||c>=65490&&c<=65495||c>=65498&&c<=65500;				
}
function validVarPart(c){	
	return c===170||c===181||c===186||c>=192&&c<=214||c>=216&&c<=246||c>=248&&c<=705||c>=710&&c<=721||c>=736&&c<=740||c===748||c===750||c>=768&&c<=884||c>=886&&c<=887||c>=890&&c<=893||c===902||c>=904&&c<=906||c===908||c>=910&&c<=929||c>=931&&c<=1013||c>=1015&&c<=1153||c>=1155&&c<=1159||c>=1162&&c<=1319||c>=1329&&c<=1366||c===1369||c>=1377&&c<=1415||c>=1425&&c<=1469||c===1471||c>=1473&&c<=1474||c>=1476&&c<=1477||c===1479||c>=1488&&c<=1514||c>=1520&&c<=1522||c>=1552&&c<=1562||c>=1568&&c<=1641||c>=1646&&c<=1747||c>=1749&&c<=1756||c>=1759&&c<=1768||c>=1770&&c<=1788||c===1791||c>=1808&&c<=1866||c>=1869&&c<=1969||c>=1984&&c<=2037||c===2042||c>=2048&&c<=2093||c>=2112&&c<=2139||c===2208||c>=2210&&c<=2220||c>=2276&&c<=2302||c>=2304&&c<=2403||c>=2406&&c<=2415||c>=2417&&c<=2423||c>=2425&&c<=2431||c>=2433&&c<=2435||c>=2437&&c<=2444||c>=2447&&c<=2448||c>=2451&&c<=2472||c>=2474&&c<=2480||c===2482||c>=2486&&c<=2489||c>=2492&&c<=2500||c>=2503&&c<=2504||c>=2507&&c<=2510||c===2519||c>=2524&&c<=2525||c>=2527&&c<=2531||c>=2534&&c<=2545||c>=2561&&c<=2563||c>=2565&&c<=2570||c>=2575&&c<=2576||c>=2579&&c<=2600||c>=2602&&c<=2608||c>=2610&&c<=2611||c>=2613&&c<=2614||c>=2616&&c<=2617||c===2620||c>=2622&&c<=2626||c>=2631&&c<=2632||c>=2635&&c<=2637||c===2641||c>=2649&&c<=2652||c===2654||c>=2662&&c<=2677||c>=2689&&c<=2691||c>=2693&&c<=2701||c>=2703&&c<=2705||c>=2707&&c<=2728||c>=2730&&c<=2736||c>=2738&&c<=2739||c>=2741&&c<=2745||c>=2748&&c<=2757||c>=2759&&c<=2761||c>=2763&&c<=2765||c===2768||c>=2784&&c<=2787||c>=2790&&c<=2799||c>=2817&&c<=2819||c>=2821&&c<=2828||c>=2831&&c<=2832||c>=2835&&c<=2856||c>=2858&&c<=2864||c>=2866&&c<=2867||c>=2869&&c<=2873||c>=2876&&c<=2884||c>=2887&&c<=2888||c>=2891&&c<=2893||c>=2902&&c<=2903||c>=2908&&c<=2909||c>=2911&&c<=2915||c>=2918&&c<=2927||c===2929||c>=2946&&c<=2947||c>=2949&&c<=2954||c>=2958&&c<=2960||c>=2962&&c<=2965||c>=2969&&c<=2970||c===2972||c>=2974&&c<=2975||c>=2979&&c<=2980||c>=2984&&c<=2986||c>=2990&&c<=3001||c>=3006&&c<=3010||c>=3014&&c<=3016||c>=3018&&c<=3021||c===3024||c===3031||c>=3046&&c<=3055||c>=3073&&c<=3075||c>=3077&&c<=3084||c>=3086&&c<=3088||c>=3090&&c<=3112||c>=3114&&c<=3123||c>=3125&&c<=3129||c>=3133&&c<=3140||c>=3142&&c<=3144||c>=3146&&c<=3149||c>=3157&&c<=3158||c>=3160&&c<=3161||c>=3168&&c<=3171||c>=3174&&c<=3183||c>=3202&&c<=3203||c>=3205&&c<=3212||c>=3214&&c<=3216||c>=3218&&c<=3240||c>=3242&&c<=3251||c>=3253&&c<=3257||c>=3260&&c<=3268||c>=3270&&c<=3272||c>=3274&&c<=3277||c>=3285&&c<=3286||c===3294||c>=3296&&c<=3299||c>=3302&&c<=3311||c>=3313&&c<=3314||c>=3330&&c<=3331||c>=3333&&c<=3340||c>=3342&&c<=3344||c>=3346&&c<=3386||c>=3389&&c<=3396||c>=3398&&c<=3400||c>=3402&&c<=3406||c===3415||c>=3424&&c<=3427||c>=3430&&c<=3439||c>=3450&&c<=3455||c>=3458&&c<=3459||c>=3461&&c<=3478||c>=3482&&c<=3505||c>=3507&&c<=3515||c===3517||c>=3520&&c<=3526||c===3530||c>=3535&&c<=3540||c===3542||c>=3544&&c<=3551||c>=3570&&c<=3571||c>=3585&&c<=3642||c>=3648&&c<=3662||c>=3664&&c<=3673||c>=3713&&c<=3714||c===3716||c>=3719&&c<=3720||c===3722||c===3725||c>=3732&&c<=3735||c>=3737&&c<=3743||c>=3745&&c<=3747||c===3749||c===3751||c>=3754&&c<=3755||c>=3757&&c<=3769||c>=3771&&c<=3773||c>=3776&&c<=3780||c===3782||c>=3784&&c<=3789||c>=3792&&c<=3801||c>=3804&&c<=3807||c===3840||c>=3864&&c<=3865||c>=3872&&c<=3881||c===3893||c===3895||c===3897||c>=3902&&c<=3911||c>=3913&&c<=3948||c>=3953&&c<=3972||c>=3974&&c<=3991||c>=3993&&c<=4028||c===4038||c>=4096&&c<=4169||c>=4176&&c<=4253||c>=4256&&c<=4293||c===4295||c===4301||c>=4304&&c<=4346||c>=4348&&c<=4680||c>=4682&&c<=4685||c>=4688&&c<=4694||c===4696||c>=4698&&c<=4701||c>=4704&&c<=4744||c>=4746&&c<=4749||c>=4752&&c<=4784||c>=4786&&c<=4789||c>=4792&&c<=4798||c===4800||c>=4802&&c<=4805||c>=4808&&c<=4822||c>=4824&&c<=4880||c>=4882&&c<=4885||c>=4888&&c<=4954||c>=4957&&c<=4959||c>=4992&&c<=5007||c>=5024&&c<=5108||c>=5121&&c<=5740||c>=5743&&c<=5759||c>=5761&&c<=5786||c>=5792&&c<=5866||c>=5870&&c<=5872||c>=5888&&c<=5900||c>=5902&&c<=5908||c>=5920&&c<=5940||c>=5952&&c<=5971||c>=5984&&c<=5996||c>=5998&&c<=6000||c>=6002&&c<=6003||c>=6016&&c<=6099||c===6103||c>=6108&&c<=6109||c>=6112&&c<=6121||c>=6155&&c<=6157||c>=6160&&c<=6169||c>=6176&&c<=6263||c>=6272&&c<=6314||c>=6320&&c<=6389||c>=6400&&c<=6428||c>=6432&&c<=6443||c>=6448&&c<=6459||c>=6470&&c<=6509||c>=6512&&c<=6516||c>=6528&&c<=6571||c>=6576&&c<=6601||c>=6608&&c<=6617||c>=6656&&c<=6683||c>=6688&&c<=6750||c>=6752&&c<=6780||c>=6783&&c<=6793||c>=6800&&c<=6809||c===6823||c>=6912&&c<=6987||c>=6992&&c<=7001||c>=7019&&c<=7027||c>=7040&&c<=7155||c>=7168&&c<=7223||c>=7232&&c<=7241||c>=7245&&c<=7293||c>=7376&&c<=7378||c>=7380&&c<=7414||c>=7424&&c<=7654||c>=7676&&c<=7957||c>=7960&&c<=7965||c>=7968&&c<=8005||c>=8008&&c<=8013||c>=8016&&c<=8023||c===8025||c===8027||c===8029||c>=8031&&c<=8061||c>=8064&&c<=8116||c>=8118&&c<=8124||c===8126||c>=8130&&c<=8132||c>=8134&&c<=8140||c>=8144&&c<=8147||c>=8150&&c<=8155||c>=8160&&c<=8172||c>=8178&&c<=8180||c>=8182&&c<=8188||c>=8204&&c<=8205||c>=8255&&c<=8256||c===8276||c===8305||c===8319||c>=8336&&c<=8348||c>=8400&&c<=8412||c===8417||c>=8421&&c<=8432||c===8450||c===8455||c>=8458&&c<=8467||c===8469||c>=8473&&c<=8477||c===8484||c===8486||c===8488||c>=8490&&c<=8493||c>=8495&&c<=8505||c>=8508&&c<=8511||c>=8517&&c<=8521||c===8526||c>=8544&&c<=8584||c>=11264&&c<=11310||c>=11312&&c<=11358||c>=11360&&c<=11492||c>=11499&&c<=11507||c>=11520&&c<=11557||c===11559||c===11565||c>=11568&&c<=11623||c===11631||c>=11647&&c<=11670||c>=11680&&c<=11686||c>=11688&&c<=11694||c>=11696&&c<=11702||c>=11704&&c<=11710||c>=11712&&c<=11718||c>=11720&&c<=11726||c>=11728&&c<=11734||c>=11736&&c<=11742||c>=11744&&c<=11775||c===11823||c>=12293&&c<=12295||c>=12321&&c<=12335||c>=12337&&c<=12341||c>=12344&&c<=12348||c>=12353&&c<=12438||c>=12441&&c<=12442||c>=12445&&c<=12447||c>=12449&&c<=12538||c>=12540&&c<=12543||c>=12549&&c<=12589||c>=12593&&c<=12686||c>=12704&&c<=12730||c>=12784&&c<=12799||c>=13312&&c<=19893||c>=19968&&c<=40908||c>=40960&&c<=42124||c>=42192&&c<=42237||c>=42240&&c<=42508||c>=42512&&c<=42539||c>=42560&&c<=42607||c>=42612&&c<=42621||c>=42623&&c<=42647||c>=42655&&c<=42737||c>=42775&&c<=42783||c>=42786&&c<=42888||c>=42891&&c<=42894||c>=42896&&c<=42899||c>=42912&&c<=42922||c>=43000&&c<=43047||c>=43072&&c<=43123||c>=43136&&c<=43204||c>=43216&&c<=43225||c>=43232&&c<=43255||c===43259||c>=43264&&c<=43309||c>=43312&&c<=43347||c>=43360&&c<=43388||c>=43392&&c<=43456||c>=43471&&c<=43481||c>=43520&&c<=43574||c>=43584&&c<=43597||c>=43600&&c<=43609||c>=43616&&c<=43638||c>=43642&&c<=43643||c>=43648&&c<=43714||c>=43739&&c<=43741||c>=43744&&c<=43759||c>=43762&&c<=43766||c>=43777&&c<=43782||c>=43785&&c<=43790||c>=43793&&c<=43798||c>=43808&&c<=43814||c>=43816&&c<=43822||c>=43968&&c<=44010||c>=44012&&c<=44013||c>=44016&&c<=44025||c>=44032&&c<=55203||c>=55216&&c<=55238||c>=55243&&c<=55291||c>=63744&&c<=64109||c>=64112&&c<=64217||c>=64256&&c<=64262||c>=64275&&c<=64279||c>=64285&&c<=64296||c>=64298&&c<=64310||c>=64312&&c<=64316||c===64318||c>=64320&&c<=64321||c>=64323&&c<=64324||c>=64326&&c<=64433||c>=64467&&c<=64829||c>=64848&&c<=64911||c>=64914&&c<=64967||c>=65008&&c<=65019||c>=65024&&c<=65039||c>=65056&&c<=65062||c>=65075&&c<=65076||c>=65101&&c<=65103||c>=65136&&c<=65140||c>=65142&&c<=65276||c>=65296&&c<=65305||c>=65313&&c<=65338||c===65343||c>=65345&&c<=65370||c>=65382&&c<=65470||c>=65474&&c<=65479||c>=65482&&c<=65487||c>=65490&&c<=65495||c>=65498&&c<=65500;				
}	
function parse(obj) {
	var code = obj.code, len = code.length, onComplete = obj.onComplete, onStateChange = obj.onStateChange,
		pos = 0, last, output = '', left = 0, state = 0, nextState = 0, lastState, states = {}, start = 0, end = 0,
		cached = 0, newLineFlag = 0,		
		statesLookup = {
				0: 'Nothing',1: 'SingleLineComment',2:'MultilineComment',3:'Regex',
				4: 'Number', 5: 'IdentifierDot', 6: 'DivideAssignment', 7: 'DivideOperator',
				8: 'Identifier', 9: 'StringSingleQuote', 10: 'StringDoubleQuote', 11: 'Operator',
				12: 'BitwiseNot', 13: 'Unknown', 14: 'Typeof', 15: 'Hex', 16: 'Ternary', 17: 'EqualAssignment',
				18: 'Not', 19: 'UnaryPlus', 20: 'Addition', 21: 'BitwiseOr', 22: 'Xor', 23: 'Modulus', 24: 'BitwiseAnd',
				25: 'EqualAssignment', 26: 'GreaterThan', 27: 'LessThan', 28: 'Multiply', 29: 'UnaryMinus', 30: 'Subtraction',
				31: 'PrefixIncrement', 32: 'NotEqual', 33: 'BitwiseLeftShift', 34: 'BitwiseLeftShiftAssignment',
				35: 'LessThanEqual', 36: 'LessThan', 37: 'BitwiseRightShift', 38: 'BitwiseZeroRightShift',
				39: 'BitwiseRightShiftAssignment', 40: 'GreaterThanEqual', 41: 'GreaterThan', 42: 'BitwiseRightZeroShift',
				43: 'BitwiseRightZeroShiftAssignment', 44: 'SubtractionAssignment', 45: 'AdditionAssignment', 46: 'LogicalOr',
				47: 'LogicalAnd', 48: 'MultiplyAssignment', 49: 'ModulusAssignment', 50: 'LogicalAndAssignment',
				51: 'LogicalOrAssignment', 52: 'XorAssignment', 53: 'EndStatement', 54: 'LabelColon', 55: 'CommaOperator',
				56: 'ArrayOpen', 57: 'AccessorOpen', 58: 'ArrayClose', 59: 'AccessorClose', 60: 'PostfixDecrement',
				61: 'PostfixIncrement', 62: 'Function'
		},
		lookupSquare = 0, lookupCurly, lookupParen = 0, lookup, parentStates = {},
		ternaryCount = 0, isTernary = {}, caseCount = 0, isCase = {}, isVar = {},
		isFor = {}, isForIn = {},  isIf = {}, isObjectLiteral = {},	expected = {},			
		//constants
		SQUARE_OPEN = 91, SQUARE_CLOSE = 93, PAREN_OPEN = 40, PAREN_CLOSE = 41,
		CURLY_OPEN = 123, CURLY_CLOSE = 125,LOWER_A = 97, LOWER_B = 98, LOWER_C = 99, LOWER_D = 100, 
		LOWER_E = 101,LOWER_F = 102, LOWER_G = 103, LOWER_H = 104, LOWER_I = 105, LOWER_J = 106,
		LOWER_K = 107, LOWER_L = 108, LOWER_M = 109, LOWER_N = 110, LOWER_O = 111,LOWER_P = 112, 
		LOWER_Q = 113, LOWER_R = 114, LOWER_S = 115, LOWER_T = 116, LOWER_U = 117, LOWER_V = 118, 
		LOWER_W = 119, LOWER_X = 120, LOWER_Y = 121, LOWER_Z = 122, UPPER_A = 65, UPPER_B = 66, 
		UPPER_C = 67, UPPER_D = 68, UPPER_E = 69, UPPER_F = 70, UPPER_G = 71, UPPER_H = 72, 
		UPPER_I = 73, UPPER_J = 74, UPPER_K = 75, UPPER_L = 76, UPPER_M = 77, UPPER_N = 78, UPPER_O = 79,
		UPPER_P = 80, UPPER_Q = 81, UPPER_R = 82, UPPER_S = 83, UPPER_T = 84, UPPER_U = 85, UPPER_V = 86, 
		UPPER_W = 87, UPPER_X = 88, UPPER_Y = 89, UPPER_Z = 90, DIGIT_0 = 48, DIGIT_1 = 49, DIGIT_2 = 50, 
		DIGIT_3 = 51, DIGIT_4 = 52, DIGIT_5 = 53, DIGIT_6 = 54, DIGIT_7 = 55, DIGIT_8 = 56, DIGIT_9 = 57, 
		DOLLAR = 36, UNDERSCORE = 95, SINGLE_QUOTE = 39, DOUBLE_QUOTE = 34, FORWARD_SLASH = 47, BACKSLASH = 92, 
		ASTERIX = 42, EQUAL = 61, CARET = 94, COLON = 58, QUESTION_MARK = 63, COMMA = 44, PERIOD = 46, 
		SEMI_COLON = 59, EXCLAMATION_MARK = 33, TILDE = 126, PLUS = 43, MINUS = 45, AMPERSAND = 38, PIPE = 124, 
		GREATER_THAN = 62, LESS_THAN = 60, PERCENT = 37, NEWLINE = 10, CARRIAGE_RETURN = 13, LINE_SEPARATOR = 8232, 
		PARAGRAPH_SEPARATOR = 8233,
		//states
		NOTHING = 0, SINGLE_LINE_COMMENT = 1, MULTI_LINE_COMMENT = 2, REGEX = 3, NUMBER = 4, IDENTIFIER_DOT = 5, 
		DIVIDE_ASSIGNMENT = 6, DIVIDE_OPERATOR = 7, IDENTIFIER = 8, STRING_SINGLE = 9, STRING_DOUBLE = 10, OPERATOR = 11,
		BITWISE_NOT = 12, UNKNOWN = 13, TYPEOF = 14, HEX = 15, TERNARY = 16, EQUAL_ASSIGNMENT = 17, NOT = 18,
		UNARY_PLUS = 19, ADDITION = 20, BITWISE_OR = 21, XOR = 22, MODULUS = 23, BITWISE_AND = 24, EQUAL_ASSIGNMENT = 25,
		GREATER_THAN_OPERATOR = 26, LESS_THAN_OPERATOR = 27, MULTIPLY = 28, UNARY_MINUS = 29, SUBTRACTION = 30,
		PREFIX_INCREMENT = 31, NOT_EQUAL = 32, BITWISE_LEFT_SHIFT = 33, BITWISE_LEFT_SHIFT_ASSIGNMENT = 34,
		LESS_THAN_EQUAL = 35, LESS_THAN_OPERATOR = 36, BITWISE_RIGHT_SHIFT = 37, BITWISE_ZERO_RIGHT_SHIFT = 38,
		BITWISE_RIGHT_SHIFT_ASSIGNMENT = 39, GREATER_THAN_EQUAL = 40, GREATER_THAN_OPERATOR = 41,
		BITWISE_RIGHT_ZERO_SHIFT = 42, BITWISE_RIGHT_ZERO_SHIFT_ASSIGNMENT = 43, SUBTRACTION_ASSIGNMENT = 44,
		ADDITION_ASSIGNMENT = 45, LOGICAL_OR = 46, LOGICAL_AND = 47, MULTIPLY_ASSIGNMENT = 48, MODULUS_ASSIGNMENT = 49,
		LOGICAL_AND_ASSIGNMENT = 50, LOGICAL_OR_ASSIGNMENT = 51, XOR_ASSIGNMENT = 52, END_STATEMENT = 53, LABEL_COLON = 54,
		COMMA_OPERATOR = 55, ARRAY_OPEN = 56, ACCESSOR_OPEN = 57, ARRAY_CLOSE = 58, ACCESSOR_CLOSE = 59,
		POSTFIX_DECREMENT = 60, POSTFIX_INCREMENT = 61, FUNCTION = 62;									
	while(pos < len) {
			if(state === NOTHING) {		
				if(cached) {
					chr = cached;
					cached = 0;
				} else {
					chr = code.charCodeAt(pos);
				}																									
				if(chr >= LOWER_A && chr <= LOWER_Z) {				
					state = IDENTIFIER;					
				} else if(chr >= UPPER_A && chr <= UPPER_Z) {
					state = IDENTIFIER;					
				} else if(chr === DOLLAR || chr === UNDERSCORE || chr === BACKSLASH) {
					state = IDENTIFIER;										
				} else if(chr === NEWLINE || chr === CARRIAGE_RETURN || chr === LINE_SEPARATOR || chr === PARAGRAPH_SEPARATOR) {
					newLineFlag = 1;
					pos++;
					continue;														
				} else if(chr === 9 || chr === 11 || chr === 12 || chr === 32 || chr === 160 || chr === 5760 || chr === 6158 || chr >= 8192 && chr <= 8202 || chr === 8239 || chr === 8287 || chr === 12288) {											
					pos++;
					continue;
				} else if(chr === SEMI_COLON) {
					state = END_STATEMENT;
				} else if(chr === PAREN_OPEN) {
					state = PAREN_OPEN;
				} else if(chr === PAREN_CLOSE) {
					state = PAREN_CLOSE;
				} else if(chr === CURLY_OPEN) {
					state = CURLY_OPEN;
				} else if(chr === CURLY_CLOSE) {
					state = CURLY_CLOSE;
				} else if(chr === SQUARE_OPEN) {
					state = SQUARE_OPEN;
				} else if(chr === SQUARE_CLOSE) {
					state = SQUARE_CLOSE;
				} else if(chr === DIGIT_0) {
					if(pos + 1 === len) {
						state = NUMBER;
					} else {
						state = UNKNOWN;
						pos++;
						last = chr;
					}
					continue;			
				} else if(chr >= DIGIT_1 && chr <= DIGIT_9) {
					state = NUMBER;					
				} else if(chr === SINGLE_QUOTE) {
					state = STRING_SINGLE;					
				} else if(chr === DOUBLE_QUOTE) {
					state = STRING_DOUBLE;
				} else if(chr === PERIOD) {
					if(left) {
						left = 0;
						state = IDENTIFIER_DOT;						
					} else {
						state = NUMBER;
					}					
				} else if(chr === FORWARD_SLASH) {
					state = UNKNOWN;
					pos++;
					last = chr;
					continue;
				} else if(chr === COLON) {
					state = LABEL_COLON;	
				} else if(chr === COMMA) {
					state = COMMA_OPERATOR;						
				} else if(chr === PLUS) {
					if(!left) {
						newState = UNARY_PLUS;	
					} else {
						newState = ADDITION;
					}										
					state = OPERATOR;
				} else if(chr === EXCLAMATION_MARK) {					
					newState = NOT;					
					state = OPERATOR;
				} else if(chr === PIPE) {
					newState = BITWISE_OR;
					state = OPERATOR;
				} else if(chr === CARET) {
					newState = XOR;
					state = OPERATOR;
				} else if(chr === PERCENT) {
					newState = MODULUS;
					state = OPERATOR;
				} else if(chr === AMPERSAND) {
					newState = BITWISE_AND;
					state = OPERATOR;
				} else if(chr === EQUAL) {
					newState = EQUAL_ASSIGNMENT;
					state = OPERATOR;
				} else if(chr === GREATER_THAN) {
					newState = GREATER_THAN_OPERATOR;
					state = OPERATOR;
				} else if(chr === LESS_THAN) {
					newState = LESS_THAN_OPERATOR;
					state = OPERATOR;
				} else if(chr === ASTERIX) {
					newState = MULTIPLY;
					state = OPERATOR;
				} else if(chr === MINUS) {
					if(!left) {
						newState = UNARY_MINUS;
					} else {
						newState = SUBTRACTION;						
					}
					state = OPERATOR;
				} else if(chr === TILDE) {
					if(!left) {
						state = BITWISE_NOT;
					} else {
						throw'Unexpected ~ Cannot follow '+lastState+'.';
					}
				} else if(chr === QUESTION_MARK) {
						state = TERNARY;
				} else if(chr > 0x80) {
					if(!validVar(chr)) {
						throw'illegal character.';
					}
					state = IDENTIFIER;	
				} else {
					throw'Unexpected character';
				}											
			}
			if(state === UNKNOWN) {				
				chr = code.charCodeAt(pos);				
				if(last === FORWARD_SLASH) {
					if(chr === FORWARD_SLASH) {
						state = SINGLE_LINE_COMMENT;
					} else if(chr === ASTERIX) {
						state = MULTI_LINE_COMMENT;
					} else if(!left) {
						state = REGEX;											
					} else if(left) {						
						newState = DIVIDE_OPERATOR;													
						state = OPERATOR;																																														
					} else {
						throw'Unknown state.';
					}
				} else if(last === DIGIT_0) {
					if(chr === LOWER_X) {
						state = HEX;
					} else if(chr === UPPER_X) {
						state = HEX;						
					} else {
						state = NUMBER;
					}
				} else {
					throw'Unknown state.';
				}								
			} 				
			switch(state) {
				case PAREN_OPEN:					
					lookupParen++;
					left = 0;
					pos++;
					output+='(';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],'(');
	            	}	            	
					parentStates[""+lookupSquare+lookupCurly+lookupParen] = lastState;
					last = PAREN_OPEN;
					state = NOTHING;
				break;
				case PAREN_CLOSE:
					parentState = parentStates[""+lookupSquare+lookupCurly+lookupParen];					
					pos++;
					output+=')';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],')');
	            	}	            	
					parentStates[""+lookupSquare+lookupCurly+lookupParen] = '';
					lookupParen--;
					last = PAREN_CLOSE;
					state = NOTHING;								
				break;
				case CURLY_OPEN:					
					lookupCurly++;
					left = 0;
					pos++;
					output+='(';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],'{');
	            	}	            	
					parentStates[""+lookupSquare+lookupCurly+lookupParen] = lastState;
					last = CURLY_OPEN;
					state = NOTHING;
				break;
				case CURLY_CLOSE:
					parentState = parentStates[""+lookupSquare+lookupCurly+lookupParen];					
					pos++;
					output+='}';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],'}');
	            	}	            	
					parentStates[""+lookupSquare+lookupCurly+lookupParen] = '';
					lookupCurly--;
					last = CURLY_CLOSE;
					state = NOTHING;								
				break;					
				case SQUARE_CLOSE:								
					parentState = parentStates[""+lookupSquare+lookupCurly+lookupParen];										
					if(parentState === ARRAY_OPEN) {
						lastState = ARRAY_CLOSE;						
					} else if(parentState === ACCESSOR_OPEN) {
						lastState = ACCESSOR_CLOSE;																		
					} else {				
						throw'Unexpected ]. Cannot follow '+lastState+'.Output:'+output;
					}	
					left = 1;
					pos++;
					output+=']';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],']');
	            	}
					last = SQUARE_CLOSE;
					state = NOTHING;
					parentStates[""+lookupSquare+lookupCurly+lookupParen] = '';
					lookupSquare--;
				break;
				case SQUARE_OPEN:
					if(!left) {
						lastState = ARRAY_OPEN;
					} else {
						lastState = ACCESSOR_OPEN;
					}
					output+='[';
					pos++;					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],'[');
	            	}
	            	lookupSquare++;	            	
	            	parentStates[""+lookupSquare+lookupCurly+lookupParen] = lastState;
	            	left = 0;
	            	last = SQUARE_OPEN;
	            	state = NOTHING;
				break;
				case END_STATEMENT:
					lastState = state;
					output+=';';
					pos++;					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],';');
	            	}
					left = 0;
					last = SEMI_COLON;
					lastState = END_STATEMENT;
					state = NOTHING;
				break;
				case COMMA_OPERATOR:
					lastState = state;
					output+=',';
					pos++;					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],',');
	            	}		
	            	left = 0;
					last = COMMA;
					state = NOTHING;			
				break;
				case LABEL_COLON:
					lastState = state;
					output+=':';
					pos++;										
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],':');
	            	}
	            	left = 0;
					last = COLON;
					state = NOTHING;					
				break;
				case TERNARY:
					lastState = state;
					output+='?';
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],"?");
	            	}
					left = 0;
					state = NOTHING;
					pos++;
				break;
				case BITWISE_NOT:
					lastState = state;
					output+='~';					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],"~");
	            	}
					state = NOTHING;
					pos++;
				break;
				case IDENTIFIER_DOT:
					lastState = state;
					output+='.';					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],".");
	            	}
					state = NOTHING;
					pos++;
				break;
				case HEX:
					left = 1;
					states = {output:'0x'};
					lastState = NUMBER;
					pos++;
					while(pos < len) {
						chr = code.charCodeAt(pos);
						if(chr >= DIGIT_0 && chr <= DIGIT_9) {
						} else if(chr >= LOWER_A && chr <= LOWER_F) {
						} else if(chr >= UPPER_A && chr <= UPPER_F) {							
						} else {
							break;
						}
						states.output+=code.charAt(pos);
						pos++;
					}
					if(states.output.length == 2) {
						throw'Missing hex digits.';
					}
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
	            	output+=states.output;
	            	cached = chr;
	            	state = NOTHING;
				break;											
				case NUMBER:
					left = 1;										
					states = {dot: 0, e:0, e2:0, complete:0,output:'', zeroFirst: 0, dotFirst: 0};
					if(chr === PERIOD) {
						states.output = '.';
						states.dot = 1;
						states.dotFirst = 1;						
					} else if(chr === DIGIT_0) {
						states.zeroFirst = 1;																		
					} else {
						states.output = code.charAt(pos);						
					}
					pos++;
					while(pos < len) {
						chr = code.charCodeAt(pos);
						if(chr >= DIGIT_1 && chr <= DIGIT_9) {
							states.zeroFirst = 0;
							if(states.e) {
								states.e = 2;
							}
							if(states.e2) {
								states.e2 = 2;
							}								
						} else if(chr === DIGIT_0) {
							if(states.zeroFirst) {
								pos++;
								continue;								
							}
							if(states.e) {
								states.e = 2;
							}
							if(states.e2) {
								states.e2 = 2;
							}
						} else if(chr === LOWER_E || chr === UPPER_E) {
							if(states.e) {
								break;
							} else {
								states.e = 1;
							}
						} else if(chr === PLUS || chr === MINUS) {
							if(states.e === 1 && !states.e2) {
								states.e = 2;
								states.e2 = 1;								
							} else {
								cached = chr;
								break;
							}
						} else if(chr === PERIOD) {
							if(states.dot || states.e) {
								break;
							}
							states.dot = 1;
						} else {
							cached = chr;
							break;
						}
						last = chr;
						states.output+=code.charAt(pos);
						pos++;
					}
					if(states.zeroFirst && !states.output.length) {
						states.output = '0';
					} else if(states.dotFirst) {
						if(states.output.length === 1) {
							throw'Expected digit';
						}
						states.output = '0' + states.output;
					} else if(states.e === 1 || states.e2 === 1) {
						throw'Expected exponent';
					}
					output += states.output;					
					lastState = NUMBER;
					state = NOTHING;
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
				break;
				case OPERATOR:																													
					last = chr;
					if(newState !== DIVIDE_OPERATOR) {
						states = {output:code.charAt(pos)};
						pos++;
					} else {
						states = {output:''};
					}																													
					operatorLoop:while(pos < len) {						
						chr = code.charCodeAt(pos);
						switch(newState) {
							case BITWISE_AND:
								if(chr === AMPERSAND) {																		
									states.output += '&';
									lastState = LOGICAL_AND;
									pos++;
									break operatorLoop;
								}else if(chr === EQUAL) {																		
									states.output += '=';
									lastState = LOGICAL_AND_ASSIGNMENT;
									pos++;
									break operatorLoop;								
								} else {
									lastState = BITWISE_AND;
									cached = chr;
									states.output += ' ';
									output += ' ';									
									break operatorLoop;
								}
							break;							
							case BITWISE_OR:
								if(chr === PIPE) {																		
									states.output += '|';
									lastState = LOGICAL_OR;
									pos++;
									break operatorLoop;	
								} else if(chr === EQUAL) {																		
									states.output += '=';
									lastState = LOGICAL_OR_ASSIGNMENT;
									pos++;
									break operatorLoop;							
								} else {
									lastState = BITWISE_OR;
									cached = chr;
									states.output += ' ';
									output += ' ';									
									break operatorLoop;
								}
							break;
							case BITWISE_LEFT_SHIFT:
								if(chr === EQUAL) {
									lastState = BITWISE_LEFT_SHIFT_ASSIGNMENT;
									pos++;									
									states.output += '=';
									break operatorLoop;
								} else {									
									lastState = BITWISE_LEFT_SHIFT;
									cached = chr;																		
									break operatorLoop;
								}
							break;
							case LESS_THAN_OPERATOR:
								if(chr === LESS_THAN) {
									newState = BITWISE_LEFT_SHIFT;									
									states.output += '<';																									
								} else if(chr === EQUAL) {
									lastState = LESS_THAN_EQUAL;
									pos++;
									states.output += '=';									
									break operatorLoop;
								} else {
									lastState = LESS_THAN_OPERATOR;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;
							case BITWISE_RIGHT_ZERO_SHIFT:
								if(chr === EQUAL) {
									lastState = BITWISE_RIGHT_ZERO_SHIFT_ASSIGNMENT;
									pos++;									
									states.output += '=';
									break operatorLoop;
								} else {									
									lastState = BITWISE_RIGHT_ZERO_SHIFT;
									cached = chr;																		
									break operatorLoop;
								}
							break;	
							case BITWISE_RIGHT_SHIFT:
								if(chr === GREATER_THAN) {									
									newState = BITWISE_RIGHT_ZERO_SHIFT;									
									states.output += '>';																										
								} else if(chr === EQUAL) {									
									lastState = BITWISE_RIGHT_SHIFT_ASSIGNMENT;
									states.output += '=';
									pos++;									
									break operatorLoop;
								} else {
									lastState = BITWISE_RIGHT_SHIFT;
									cached = chr;																		
									break operatorLoop;
								}
							break;
							case GREATER_THAN_OPERATOR:
								if(chr === GREATER_THAN) {
									newState = BITWISE_RIGHT_SHIFT;									
									states.output += '>';																										
								} else if(chr === EQUAL) {
									lastState = GREATER_THAN_EQUAL;
									pos++;
									states.output += '=';									
									break operatorLoop;
								} else {
									lastState = GREATER_THAN_OPERATOR;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;	
							case DIVIDE_OPERATOR:																																			
								if(chr === EQUAL) {
									lastState = DIVIDE_ASSIGNMENT;
									pos++;
									states.output += '/=';
									break operatorLoop;							
								} else {
									lastState = DIVIDE_OPERATOR;
									cached = chr;																		
									states.output += ' / ';																											
									break operatorLoop;
								}
							break;	
							case XOR:
								if(chr === EQUAL) {
									lastState = XOR_ASSIGNMENT;
									pos++;
									states.output += '=';
									break operatorLoop;							
								} else {
									lastState = XOR;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;																
							case MODULUS:
								if(chr === EQUAL) {
									lastState = MODULUS_ASSIGNMENT;
									pos++;
									states.output += '=';
									break operatorLoop;							
								} else {
									lastState = MODULUS;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;
							case MULTIPLY:
								if(chr === EQUAL) {
									lastState = MULTIPLY_ASSIGNMENT;
									pos++;
									states.output += '=';
									break operatorLoop;							
								} else {
									lastState = MULTIPLY;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;				
							case SUBTRACTION:
								if(chr === MINUS) {
									lastState = POSTFIX_DECREMENT;
									pos++;
									states.output += '-';
									break operatorLoop;
								} else if(chr === EQUAL) {
									lastState = SUBTRACTION_ASSIGNMENT;
									pos++;
									states.output += '=';
									break operatorLoop;
								} else {
									lastState = SUBTRACTION;
									cached = chr;																		
									states.output += ' ';
									output += ' ';
									break operatorLoop;
								}
							break;
							case ADDITION:
								if(chr === PLUS) {
									lastState = POSTFIX_INCREMENT;
									pos++;
									states.output += '+';
									break operatorLoop;
								} else if(chr === EQUAL) {
									lastState = ADDITION_ASSIGNMENT;
									pos++;
									states.output += '=';
									break operatorLoop;
								} else {
									lastState = ADDITION;
									cached = chr;
									states.output += ' ';
									output += ' ';																		
									break operatorLoop;
								}
							break;
							case UNARY_PLUS:
								if(chr === PLUS) {
									lastState = PREFIX_INCREMENT;
									pos++;
									states.output += '+';
									break operatorLoop;								
								} else {
									lastState = UNARY_PLUS;
									cached = chr;									
									break operatorLoop;
								}
							break;
							case UNARY_MINUS:
								if(chr === MINUS) {
									lastState = PREFIX_INCREMENT;
									pos++;
									states.output += '-';
									break operatorLoop;								
								} else {
									lastState = UNARY_MINUS;
									cached = chr;									
									break operatorLoop;
								}
							case NOT:
								if(chr === EQUAL) {																		
									states.output += '=';
									newState = NOT_EQUAL;							
								} else {
									states.output += ' ';
									output += ' ';
									lastState = NOT;
									cached = chr;									
									break operatorLoop;
								}
							break;
							case NOT_EQUAL:
								if(chr === EQUAL) {
									lastState = STRICT_NOT_EQUAL;
									pos++;
									states.output += '=';
									break operatorLoop;								
								} else {
									lastState = NOT_EQUAL;
									cached = chr;									
									break operatorLoop;
								}
							break;							
							default:
								throw'Unknown operator state.';
							break
						}
						pos++;												
					} 
					state = NOTHING;
					if(onStateChange) {						
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
	            	output+=states.output;	            	
				break;
				case IDENTIFIER:
					states = {cc:[],u:0,currentIdentifier:'',currentUnicode:'',unicodeEscape:0,identifierStart:1};																				
					state = IDENTIFIER;	
					left = 1;				
					if(chr === BACKSLASH) {												
						states.identifierStart = 0;						
					}
					cached = chr;																														
					do {
						if(cached) {
							chr = cached;
							cached = 0;
						} else {
							chr = code.charCodeAt(pos);
						}												
						if(states.unicodeEscape > 1) {
							if(states.currentUnicode.length === 3) {								
								states.currentUnicode+=code.charAt(pos);
								states.u = +('0x'+states.currentUnicode);																		
								if(!states.identifierStart) {						
									if(states.u >= LOWER_A && states.u <= LOWER_Z) {						                            
									} else if(states.u >= UPPER_A && states.u <= UPPER_Z) {			                				                			                	                  
					                } else if(states.u === UNDERSCORE || states.u === DOLLAR){			                	
					                } else if(states.u > 0x80){
					                	if(!validVar(states.u)) {
					                      throw'illegal unicode escape';
					                    } 
					                } else {
					                	throw'illegal unicode escape';
					                }			                
					            } else {
					            	if(states.u >= LOWER_A && states.u <= LOWER_Z) {						                            
									} else if(states.u >= UPPER_A && states.u <= UPPER_Z) {			                	
					                } else if(states.u >= DIGIT_0 && states.u <= DIGIT_9) {			                	                  
					                } else if(states.u === UNDERSCORE || states.u === DOLLAR){			                	
					                } else if(states.u > 0x80){
					                	if(!validVarPart(states.u)) {
					                      throw'illegal unicode escape';
					                    } 
					                } else {
					                	throw'illegal unicode escape';
					                }
					            }
					            states.currentUnicode = '';
								states.unicodeEscape = 0;
								states.identifierStart = 1;
							} else if(chr >= DIGIT_0 && chr <= DIGIT_9) {
							} else if(chr >= LOWER_A && chr <= LOWER_F) {					
							} else if(chr >= UPPER_A && chr <= UPPER_F) {
							} else {
								throw'Unexpected "'+(isNaN(chr)?'(end)':chr)+'" character. Expected unicode escape.';
							}
							if(states.currentUnicode.length<4) {
								states.currentUnicode+=code.charAt(pos);
							}
						} else if(states.unicodeEscape === 1) {
			            	if(chr !== LOWER_U) {
			            		throw'Unexpected "'+(isNaN(chr)?'(end)':chr)+'" character. Expected unicode escape.';
			            	}
			            	states.unicodeEscape = 2;
						} else if(chr >= LOWER_A && chr <= LOWER_Z) {												                            
			            } else if(chr >= UPPER_A && chr <= UPPER_Z) {			            	
			            } else if(chr >= DIGIT_0 && chr <= DIGIT_9) {			            	                     
			            } else if(chr === UNDERSCORE || chr === DOLLAR) {			            	                                                      
			            } else if(chr === BACKSLASH && states.unicodeEscape) {
			            	throw'Unexpected unicode escape';
			            } else if(chr === BACKSLASH && !states.unicodeEscape) {
			            	states.unicodeEscape = 1;
			            } else if(chr > 0x80) {
			                if(!validVarPart(chr)) {
			                   cached = chr;
			                   break;
			                }                                    
			            } else {
			            	cached = chr;                	                
			            	break;
			            }
			            states.currentIdentifier+=code.charAt(pos);
			            states.cc.push(chr);
			            pos++;
		            } while(pos < len);		            		            
	            	states.identifierLen = states.currentIdentifier.length;
	            	state = NOTHING;
	    			lastState = IDENTIFIER;	    			
					switch(states.identifierLen) {
	            		case 2:	            			
	            			if(states.cc[0] === LOWER_D && states.cc[1] === LOWER_O) {                				
	            				lastState = DO;                				                					            			
	            			} else if(states.cc[0] === LOWER_I && states.cc[1] === LOWER_N) {
	            				lastState = IN;                				                				                				
	            			}
	            		break;
	            		case 3:                				            			
	            			if(states.cc[0] === LOWER_V && states.cc[1] === LOWER_A && states.cc[2] === LOWER_R) {
	            				lastState = VAR;	            			
	            			} else if(states.cc[0] === LOWER_N && states.cc[1] === LOWER_E && states.cc[2] === LOWER_W) {
	            				lastState = NEW;	            			
	            			} else if(states.cc[0] === UPPER_N && states.cc[1] === LOWER_A && states.cc[2] === UPPER_N) {
	            				lastState = NAN;
	            			} 
	            		break;
	            		case 4:                				            			
	            			if(states.cc[0] === LOWER_E && states.cc[1] === LOWER_L && states.cc[2] === LOWER_S && states.cc[3] === LOWER_E) {
	            				lastState = ELSE;	            			
	            			} else if(states.cc[0] === LOWER_T && states.cc[1] === LOWER_H && states.cc[2] === LOWER_I && states.cc[3] === LOWER_S) {
	            				lastState = THIS;	            			
	            			} else if(states.cc[0] === LOWER_V && states.cc[1] === LOWER_O && states.cc[2] === LOWER_I && states.cc[3] === LOWER_D) {
	            				lastState = VOID;                				            			
	            			} else if(states.cc[0] === LOWER_C && states.cc[1] === LOWER_A && states.cc[2] === LOWER_S && states.cc[3] === LOWER_E) {
	            				lastState = CASE;	            			
	            			} else if(states.cc[0] === LOWER_N && states.cc[1] === LOWER_U && states.cc[2] === LOWER_L && states.cc[3] === LOWER_L) {
	            				lastState = NULL;	            			
	            			} else if(states.cc[0] === LOWER_T && states.cc[1] === LOWER_R && states.cc[2] === LOWER_U && states.cc[3] === LOWER_E) {
	            				lastState = TRUE;
	            			}
	            		break;
	            		case 5:                				            			
	            			if(states.cc[0] === LOWER_T && states.cc[1] === LOWER_H && states.cc[2] === LOWER_R && states.cc[3] === LOWER_O && states.cc[4] === LOWER_W) {
	            				lastState = THROW;	            			
	            			} else if(states.cc[0] === LOWER_B && states.cc[1] === LOWER_R && states.cc[2] === LOWER_E && states.cc[3] === LOWER_A && states.cc[4] === LOWER_K) {
	            				lastState = BREAK;	            			
	            			} else if(states.cc[0] === LOWER_F && states.cc[1] === LOWER_A && states.cc[2] === LOWER_L && states.cc[3] === LOWER_S && states.cc[4] === LOWER_E) {
	            				lastState = FALSE;
	            			}
	            		break;
	            		case 6:                				            			
	            			if(states.cc[0] === LOWER_D && states.cc[1] === LOWER_E && states.cc[2] === LOWER_L && states.cc[3] === LOWER_E && states.cc[4] === LOWER_T && states.cc[5] === LOWER_E) {
	            				lastState = DELETE;	            			
	            			} else if(states.cc[0] === LOWER_R && states.cc[1] === LOWER_E && states.cc[2] === LOWER_T && states.cc[3] === LOWER_U && states.cc[4] === LOWER_R && states.cc[5] === LOWER_N) {
	            				lastState = RETURN;	            			
	            			} else if(states.cc[0] === LOWER_T && states.cc[1] === LOWER_Y && states.cc[2] === LOWER_P && states.cc[3] === LOWER_E && states.cc[4] === LOWER_O && states.cc[5] === LOWER_F) {	            				
	            				lastState = TYPEOF;
	            			}
	            		break;
	            		case 7:	            			
	            			if(states.cc[0] === LOWER_D && states.cc[1] === LOWER_E && states.cc[2] === LOWER_F && states.cc[3] === LOWER_A && states.cc[4] === LOWER_U && states.cc[5] === LOWER_L && states.cc[6] === LOWER_T) {
	            				lastState = DEFAULT;
	            			}
	            		break;
	            		case 8:                				            			
	            			if(states.cc[0] === LOWER_F && states.cc[1] === LOWER_U && states.cc[2] === LOWER_N && states.cc[3] === LOWER_C && states.cc[4] === LOWER_T && states.cc[5] === LOWER_I && states.cc[6] === LOWER_O && states.cc[7] === LOWER_N) {
	            				lastState = FUNCTION;	            			
	            			} else if(states.cc[0] === UPPER_I && states.cc[1] === LOWER_N && states.cc[2] === LOWER_F && states.cc[3] === LOWER_I && states.cc[4] === LOWER_N && states.cc[5] === LOWER_I && states.cc[6] === LOWER_T && states.cc[7] === LOWER_Y) {
	            				lastState = INFINITY;	            			
	            			} else if(states.cc[0] === LOWER_C && states.cc[1] === LOWER_O && states.cc[2] === LOWER_N && states.cc[3] === LOWER_T && states.cc[4] === LOWER_I && states.cc[5] === LOWER_N && states.cc[6] === LOWER_U && states.cc[7] === LOWER_E) {
	            				lastState = CONTINUE;
	            			}
	            		break;
	            		case 9:	            			
	            			if(states.cc[0] === LOWER_U && states.cc[1] === LOWER_N && states.cc[2] === LOWER_D && states.cc[3] === LOWER_E && states.cc[4] === LOWER_F && states.cc[5] === LOWER_I && states.cc[6] === LOWER_N && states.cc[7] === LOWER_E && states.cc[7] === LOWER_D) {
	            				lastState = UNDEFINED;
	            			}
	            		break;                		
	            	}	            		            		            	
	            	output+=states.currentIdentifier;
	            	if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.currentIdentifier);
	            	}	            	               	                	                	                	        			                			                   		                     		            
				break;
				case REGEX:					
					left = 1;
					states = {regexOpen:1,regexSquare:0,escaping:0,regexI:0,regexG:0,regexM:0,output:'/'};
					cached = chr;
					lastState = REGEX;										
					while(pos < len) {
						if(cached) {
							chr = cached;
							cached = 0;
						} else {
							chr = code.charCodeAt(pos);
						}
						if(!states.regexOpen) {					
							if(chr === LOWER_I && !states.regexI) {
								states.regexI = 1;						
							} else if(chr === LOWER_G && !states.regexG) {
								states.regexG = 1;
							} else if(chr === LOWER_M && !states.regexM) {
								states.regexM = 1;
							} else {
								state = states.regexI = states.regexG = states.regexM = NOTHING;
								cached = chr;												
								break;
							}				
						} else if(chr === NEWLINE || chr === CARRIAGE_RETURN || chr === LINE_SEPARATOR || chr === PARAGRAPH_SEPARATOR) {
							throw'Unterminated regex';
						} else if(chr === FORWARD_SLASH && !states.escaping && !states.regexSquare) {
							states.regexOpen = 0;					
						} else if(chr === FORWARD_SLASH && !states.escaping && states.regexSquare) {
							states.output+='\\';					
						} else if(chr === BACKSLASH) {
							states.escaping = 1;
						} else if(chr === SQUARE_CLOSE && last === SQUARE_OPEN) {
							throw'Empty regex character classes are not allowed.';
						} else if(chr === SQUARE_CLOSE && last === CARET) {					
							if(code.charCodeAt(pos-2) === SQUARE_OPEN) {
								throw'Empty regex character classes are not allowed.';
							} else {
								regexSquare = 0;
							}
						} else if(chr === SQUARE_OPEN) {
							states.regexSquare = 1;
						} else if(chr === SQUARE_CLOSE && !states.escaping && states.regexSquare) {
							states.regexSquare = 0;
						} else {
							states.escaping = 0;
						}
						states.output+=code.charAt(pos);
						pos++;
					}
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
	            	state = NOTHING;
	            	output+=states.output;	
				break;				
				case MULTI_LINE_COMMENT:
					pos=code.indexOf('*/',pos);
					if(pos >= 0) {
						pos+=2;
						state = NOTHING;
					} else {												
						throw'Unterminated comment';
					}
				break;				
				case SINGLE_LINE_COMMENT:
					states = {c:0,c2:0};
					states.c=code.indexOf('\n',pos);
					states.c2=code.indexOf('\r',pos);
					if(states.c2 > 0 && states.c2 < states.c) {
						states.c = states.c2;
					}
					states.c2=code.indexOf('\u2028',pos);
					if(states.c2 > 0 && states.c2 < states.c) {
						states.c = states.c2;
					}
					states.c2=code.indexOf('\u2029',pos);
					if(states.c2 > 0 && states.c2 < states.c) {
						states.c = states.c2;
					}			
					if(states.c < 0) {
						pos = len;
					} else {																	
						pos = states.c;
					}
					state = NOTHING;					
				break;
				case STRING_DOUBLE:
					left = 1;
					states = {escaping:0,output:code.charAt(pos),open:1};
					lastState = state;
					pos++;																								
					while(pos < len) {
						chr = code.charCodeAt(pos);									
						if(chr === NEWLINE || chr === CARRIAGE_RETURN || chr === LINE_SEPARATOR || chr === PARAGRAPH_SEPARATOR) {													
							throw'Unterminated string literal';													
						} else if(chr === DOUBLE_QUOTE) {							
							if(!states.escaping) {
								states.open = 0;								
							} else {
								states.escaping = 0;
							}						
						} else if(!states.escaping && chr === BACKSLASH) {							
							states.escaping = 1;																											
						} else {
							states.escaping = 0;
						} 
						states.output+=code.charAt(pos);
						pos++;
						if(!states.open) {
							break;
						}
					}
					if(states.open) {
						throw'Unterminated string literal';
					}					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
	            	output+=states.output;
	            	state = NOTHING;
				break;
				case STRING_SINGLE:
					left = 1;
					states = {escaping:0,output:code.charAt(pos),open:1};
					lastState = state;
					pos++;																								
					while(pos < len) {
						chr = code.charCodeAt(pos);									
						if(chr === NEWLINE || chr === CARRIAGE_RETURN || chr === LINE_SEPARATOR || chr === PARAGRAPH_SEPARATOR) {													
							throw'Unterminated string literal';													
						} else if(chr === SINGLE_QUOTE) {														
							if(!states.escaping) {								
								states.open = 0;																
							} else {
								states.escaping = 0;
							}						
						} else if(!states.escaping && chr === BACKSLASH) {							
							states.escaping = 1;																											
						} else {
							states.escaping = 0;
						} 
						states.output+=code.charAt(pos);
						pos++;
						if(!states.open) {
							break;
						}
					}					
					if(states.open) {
						throw'Unterminated string literal';
					}					
					if(onStateChange) {
	            		onStateChange(statesLookup[lastState],states.output);
	            	}
	            	output+=states.output;
	            	state = NOTHING;
				break;
				default:
					throw'Unknown state:'+state+', chr:'+chr;
				break;			
			}						
	}
	
	if(onComplete) {
		onComplete();
	}		
	return output;
}
function convert() {
	var parseTree = [],
	 	start = +new Date;
	try {
		document.getElementById('output').value = parse({
			code:document.getElementById('input').value,
			onStateChange:function(state,text) {
				parseTree.push('<'+state+'>'+text+'</'+state+'>');
			},
			onComplete:function(){
				var end = +new Date;
				document.getElementById('parseTree').value = parseTree.join('\n');
				document.getElementById('parseTime').textContent = end-start+'ms';
			}
		});
	} catch(e){ 
		document.getElementById('output').value = e;
	}	
}
</script>
</head>
<body>
Input:<br />	
<textarea id="input"></textarea>
<p></p>
Output:<br />	
<textarea id="output"></textarea>
<p></p>
Parse tree:<br />	
<textarea id="parseTree"></textarea>
<p>
	<input type="button" value="Convert" onclick="convert()"/>
	<span id="parseTime"></span>
</p>
</body>
</html>